<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>时间序列预测工具</title>
    <script src="js/chart.min.js"></script>
    <script src="js/chartjs-plugin-zoom.min.js"></script>
    <script src="js/regression.min.js"></script>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        body {
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
            padding: 20px;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background-color: white;
            border-radius: 10px;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
            padding: 30px;
        }
        h1 {
            text-align: center;
            margin-bottom: 20px;
            color: #2c3e50;
        }
        .description {
            text-align: center;
            margin-bottom: 30px;
            color: #7f8c8d;
        }
        .input-section {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin-bottom: 30px;
        }
        .input-group {
            flex: 1;
            min-width: 300px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #2c3e50;
        }
        textarea, input, select {
            width: 100%;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 16px;
            transition: border-color 0.3s;
        }
        textarea:focus, input:focus, select:focus {
            outline: none;
            border-color: #3498db;
        }
        textarea {
            height: 150px;
            resize: vertical;
        }
        button {
            background-color: #3498db;
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            transition: background-color 0.3s;
            margin-top: 10px;
        }
        button:hover {
            background-color: #2980b9;
        }
        .tabs {
            display: flex;
            margin-bottom: 20px;
            border-bottom: 1px solid #ddd;
        }
        .tab {
            padding: 12px 24px;
            cursor: pointer;
            font-weight: 600;
            border-bottom: 3px solid transparent;
            transition: all 0.3s;
        }
        .tab.active {
            color: #3498db;
            border-bottom: 3px solid #3498db;
        }
        .tab-content {
            display: none;
            padding: 20px 0;
        }
        .tab-content.active {
            display: block;
        }
        .chart-container {
            position: relative;
            height: 500px;
            width: 100%;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }
        th, td {
            padding: 12px 15px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        th {
            background-color: #f8f9fa;
            font-weight: 600;
            color: #2c3e50;
        }
        tr:hover {
            background-color: #f8f9fa;
        }
        .prediction-info {
            background-color: #e8f4fd;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 20px;
        }
        .footer {
            text-align: center;
            margin-top: 30px;
            color: #7f8c8d;
            font-size: 14px;
        }
        .algorithm-options {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 10px;
            margin-top: 10px;
        }
        .algorithm-option {
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            text-align: center;
            cursor: pointer;
            transition: all 0.3s;
        }
        .algorithm-option.selected {
            background-color: #3498db;
            color: white;
            border-color: #3498db;
        }
        .confidence-interval {
            margin-top: 10px;
            font-size: 14px;
            color: #7f8c8d;
        }
        .confidence-input {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .confidence-input input {
            width: 80px;
        }
        .data-format-info {
            margin-top: 10px;
            font-size: 14px;
            color: #7f8c8d;
        }
        .period-adjustment {
            margin-top: 10px;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .period-adjustment input {
            width: 100px;
        }
        .warning {
            color: #e74c3c;
            font-size: 14px;
            margin-top: 5px;
        }
        .chart-controls {
            display: flex;
            gap: 10px;
            margin-bottom: 10px;
        }
        .chart-controls button {
            margin-top: 0;
            padding: 8px 16px;
            font-size: 14px;
        }
        .period-hint {
            color: #f39c12;
            font-size: 13px;
            margin-top: 5px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>时间序列预测工具</h1>
        <p class="description">输入历史数据，自动识别趋势并预测未来值</p>
        
        <div class="input-section">
            <div class="input-group">
                <label for="dataInput">历史数据（格式：时间 数值）</label>
                <textarea id="dataInput">月份	销量
2025-10	372
2025-09	265
2025-08	116
2025-07	91
2025-06	110
2025-05	111
2025-04	129
2025-03	158
2025-02	262
2025-01	690
2024-12	1,723
2024-11	817
2024-10	404
2024-09	111
2024-08	102
2024-07	71
2024-06	87
2024-05	103
2024-04	222
2024-03	346
2024-02	401
2024-01	1,349
2023-12	2,083
2023-11	2,168
2023-10	1,341
2023-09	288
2023-08	122
2023-07	102
2023-06	64
2023-05	96
2023-04	176
2023-03	374
2023-02	826
2023-01	1,040
2022-12	1,975
2022-11	1,697
2022-10	1,080
2022-09	316
2022-08	155
2022-07	93
2022-06	128
2022-05	182
2022-04	214
2022-03	300
2022-02	645
2022-01	2,917
2021-12	1,136
2021-11	600
2021-10	243</textarea>
                <div class="data-format-info">
                    支持的日期格式：yyyy-mm-dd, yyyy/mm/dd, yyyy-mm, yyyy/mm等
                </div>
            </div>
            
            <div class="input-group">
                <label for="futurePoints">预测未来数据点数</label>
                <input type="number" id="futurePoints" value="4" min="1" max="365">
                
                <label for="predictionType">预测类型</label>
                <select id="predictionType" style="width: 100%; padding: 12px; border-radius: 5px; font-size: 16px;">
                    <option value="auto">自动识别（推荐）</option>
                    <option value="linear">线性预测</option>
                    <option value="seasonal">周期性预测</option>
                </select>
                
                <label>预测算法</label>
                <div class="algorithm-options">
                    <div class="algorithm-option" data-algorithm="logarithmic">对数变换法</div>
                    <div class="algorithm-option" data-algorithm="exponential">指数平滑法</div>
                    <div class="algorithm-option selected" data-algorithm="polynomial">多项式回归</div>
                    <div class="algorithm-option" data-algorithm="yoy">环比增长法</div>
                </div>
                
                <div class="confidence-interval">
                    <div class="confidence-input">
                        <input type="checkbox" id="showConfidence">
                        <label for="showConfidence">显示置信区间</label>
                        <input type="number" id="confidenceLevel" value="95" min="50" max="99" step="1" style="width: 80px;">
                        <label for="confidenceLevel">%</label>
                    </div>
                </div>
                
                <div class="period-adjustment">
                    <input type="checkbox" id="manualPeriod" style="width: auto;">
                    <label for="manualPeriod">手动设置周期</label>
                    <input type="number" id="manualPeriodValue" value="7" min="1" max="365" style="width: 80px;">
                    <div class="period-hint">✨ 自动检测波峰间隔作为周期，也可手动调整</div>
                </div>
                
                <div class="period-adjustment">
                    <input type="checkbox" id="enableRandomness" style="width: auto;">
                    <label for="enableRandomness">启用随机波动</label>
                    <label for="randomnessRange">波动范围 ±</label>
                    <input type="number" id="randomnessRange" value="5" min="0" max="50" step="1" style="width: 60px;">
                    <label for="randomnessRange">%</label>
                    <div class="period-hint">模拟真实场景的不确定性，适用于环比增长法</div>
                </div>
                
                <button id="predictBtn">开始预测</button>
            </div>
        </div>
        
        <div class="prediction-info" id="predictionInfo">
            请点击"开始预测"按钮生成预测结果
        </div>
        
        <div class="tabs">
            <div class="tab active" data-tab="chart">图表</div>
            <div class="tab" data-tab="table">数据表</div>
        </div>
        
        <div class="tab-content active" id="chartTab">
            <div class="chart-controls">
                <button id="resetZoomBtn">重置缩放</button>
                <button id="zoomInBtn">放大</button>
                <button id="zoomOutBtn">缩小</button>
            </div>
            <div class="chart-container">
                <canvas id="predictionChart"></canvas>
            </div>
        </div>
        
        <div class="tab-content" id="tableTab">
            <table id="predictionTable">
                <thead>
                    <tr>
                        <th id="tableHeaderX">日期</th>
                        <th id="tableHeaderY">数值</th>
                        <th>类型</th>
                        <th>置信区间</th>
                    </tr>
                </thead>
                <tbody id="tableBody">
                    <!-- 表格数据将通过JavaScript动态生成 -->
                </tbody>
            </table>
        </div>
        
        <div class="footer">
            <p>时间序列预测工具 &copy; 2023 | 支持多种预测算法和图表缩放</p>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 标签页切换
            const tabs = document.querySelectorAll('.tab');
            tabs.forEach(tab => {
                tab.addEventListener('click', function() {
                    // 移除所有标签和内容的active类
                    document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                    document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
                    
                    // 为当前标签和对应内容添加active类
                    this.classList.add('active');
                    const tabId = this.getAttribute('data-tab');
                    document.getElementById(tabId + 'Tab').classList.add('active');
                });
            });
            
            // 算法选择
            const algorithmOptions = document.querySelectorAll('.algorithm-option');
            let selectedAlgorithm = 'polynomial'; // 默认使用多项式回归
            
            algorithmOptions.forEach(option => {
                option.addEventListener('click', function() {
                    algorithmOptions.forEach(opt => opt.classList.remove('selected'));
                    this.classList.add('selected');
                    selectedAlgorithm = this.getAttribute('data-algorithm');
                });
            });
            
            // 预测按钮点击事件
            document.getElementById('predictBtn').addEventListener('click', function() {
                performPrediction();
            });
            
            // 图表控制按钮
            document.getElementById('resetZoomBtn').addEventListener('click', function() {
                if (predictionChart) {
                    predictionChart.resetZoom();
                }
            });
            
            document.getElementById('zoomInBtn').addEventListener('click', function() {
                if (predictionChart) {
                    predictionChart.zoom(1.1);
                }
            });
            
            document.getElementById('zoomOutBtn').addEventListener('click', function() {
                if (predictionChart) {
                    predictionChart.zoom(0.9);
                }
            });
            
            // 初始化图表
            let predictionChart = null;
            
            // 执行预测函数
            function performPrediction() {
                // 获取输入数据
                const dataInput = document.getElementById('dataInput').value;
                const futurePoints = parseInt(document.getElementById('futurePoints').value);
                const predictionType = document.getElementById('predictionType').value;
                const showConfidence = document.getElementById('showConfidence').checked;
                const confidenceLevel = parseInt(document.getElementById('confidenceLevel').value);
                const manualPeriod = document.getElementById('manualPeriod').checked;
                const manualPeriodValue = parseInt(document.getElementById('manualPeriodValue').value);
                const enableRandomness = document.getElementById('enableRandomness').checked;
                const randomnessRange = parseInt(document.getElementById('randomnessRange').value) / 100;
                
                // 解析数据
                const parseResult = parseData(dataInput);
                if (!parseResult || parseResult.data.length === 0) {
                    alert('数据格式错误，请检查输入数据！');
                    return;
                }
                
                const data = parseResult.data;
                const xLabel = parseResult.xLabel;
                const yLabel = parseResult.yLabel;
                const dataFrequency = parseResult.dataFrequency;
                const dateFormat = parseResult.dateFormat;
                
                // 数据排序（确保正序）
                data.sort((a, b) => a.date - b.date);
                
                // 自动检测周期并更新UI（如果未手动设置）
                if (!manualPeriod) {
                    const y = data.map(d => d.value);
                    const detectedPeriod = detectPeriodicity(y, dataFrequency);
                    document.getElementById('manualPeriodValue').value = detectedPeriod;
                    console.log(`✅ 自动检测周期: ${detectedPeriod}`);
                }
                
                // 预测
                const predictionResult = predict(data, futurePoints, predictionType, selectedAlgorithm, confidenceLevel, manualPeriod, manualPeriodValue, dataFrequency, dateFormat, enableRandomness, randomnessRange);
                
                // 显示预测信息
                displayPredictionInfo(predictionResult, dataFrequency);
                
                // 显示表格
                displayTable(data, predictionResult, showConfidence, xLabel, yLabel);
                
                // 显示图表
                displayChart(data, predictionResult, showConfidence, xLabel, yLabel);
            }
            
            // 解析数据函数
            function parseData(input) {
                const lines = input.trim().split('\n');
                const data = [];
                
                // 检查第一行是否为标题行
                let startIndex = 0;
                let xLabel = "日期";
                let yLabel = "数值";
                let dateFormat = null;
                
                if (lines.length > 0) {
                    const firstLine = lines[0].trim();
                    // 检查第一行是否包含非数字字符（可能是标题）
                    if (/[^\d\s\-\.\/\\,]/.test(firstLine)) {
                        const parts = firstLine.split(/\s+/);
                        if (parts.length >= 2) {
                            xLabel = parts[0];
                            yLabel = parts[1];
                        }
                        startIndex = 1; // 跳过标题行
                    }
                }
                
                for (let i = startIndex; i < lines.length; i++) {
                    const line = lines[i].trim();
                    if (!line) continue;
                    
                    const parts = line.split(/\s+/);
                    if (parts.length < 2) continue;
                    
                    const dateStr = parts[0];
                    let valueStr = parts[1];
                    
                    // 处理千位分隔符
                    valueStr = valueStr.replace(/,/g, '');
                    
                    // 解析日期
                    const date = parseDate(dateStr);
                    if (!date) continue;
                    
                    // 解析数值
                    const value = parseFloat(valueStr);
                    
                    if (!isNaN(value)) {
                        data.push({
                            date: date,
                            dateStr: dateStr,
                            value: value
                        });
                        
                        // 记录第一个有效日期的格式
                        if (!dateFormat) {
                            dateFormat = detectDateFormat(dateStr);
                        }
                    }
                }
                
                // 分析数据频率
                const dataFrequency = analyzeDataFrequency(data);
                
                return {
                    data: data,
                    xLabel: xLabel,
                    yLabel: yLabel,
                    dataFrequency: dataFrequency,
                    dateFormat: dateFormat
                };
            }
            
            // 检测日期格式
            function detectDateFormat(dateStr) {
                // 检测日期分隔符和格式
                if (dateStr.includes('-')) {
                    const parts = dateStr.split('-');
                    if (parts.length === 3) {
                        return 'yyyy-mm-dd';
                    } else if (parts.length === 2) {
                        return 'yyyy-mm';
                    }
                } else if (dateStr.includes('/')) {
                    const parts = dateStr.split('/');
                    if (parts.length === 3) {
                        return 'yyyy/mm/dd';
                    } else if (parts.length === 2) {
                        return 'yyyy/mm';
                    }
                }
                
                // 默认格式
                return 'yyyy-mm-dd';
            }
            
            // 分析数据频率
            function analyzeDataFrequency(data) {
                if (data.length < 2) {
                    return { type: 'unknown', value: 1 };
                }
                
                // 计算日期之间的平均间隔（毫秒）
                const intervals = [];
                for (let i = 1; i < data.length; i++) {
                    const interval = data[i].date - data[i - 1].date;
                    intervals.push(interval);
                }
                
                const avgInterval = intervals.reduce((sum, val) => sum + val, 0) / intervals.length;
                
                // 转换为天数
                const avgDays = avgInterval / (1000 * 60 * 60 * 24);
                
                // 判断频率类型
                if (avgDays < 1.5) {
                    // 每日数据
                    return { type: 'daily', value: 1 };
                } else if (avgDays >= 6 && avgDays <= 8) {
                    // 每周数据
                    return { type: 'weekly', value: 7 };
                } else if (avgDays >= 28 && avgDays <= 31) {
                    // 每月数据
                    return { type: 'monthly', value: 30 };
                } else if (avgDays >= 89 && avgDays <= 92) {
                    // 每季度数据
                    return { type: 'quarterly', value: 90 };
                } else if (avgDays >= 360 && avgDays <= 370) {
                    // 每年数据
                    return { type: 'yearly', value: 365 };
                } else {
                    // 未知频率
                    return { type: 'unknown', value: Math.round(avgDays) };
                }
            }
            
            // 日期解析函数
            function parseDate(dateStr) {
                // 尝试多种日期格式
                
                // 格式: yyyy-mm-dd
                let match = dateStr.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
                if (match) {
                    return new Date(parseInt(match[1]), parseInt(match[2]) - 1, parseInt(match[3]));
                }
                
                // 格式: yyyy/mm/dd
                match = dateStr.match(/^(\d{4})\/(\d{1,2})\/(\d{1,2})$/);
                if (match) {
                    return new Date(parseInt(match[1]), parseInt(match[2]) - 1, parseInt(match[3]));
                }
                
                // 格式: yyyy-mm
                match = dateStr.match(/^(\d{4})-(\d{1,2})$/);
                if (match) {
                    return new Date(parseInt(match[1]), parseInt(match[2]) - 1, 1);
                }
                
                // 格式: yyyy/mm
                match = dateStr.match(/^(\d{4})\/(\d{1,2})$/);
                if (match) {
                    return new Date(parseInt(match[1]), parseInt(match[2]) - 1, 1);
                }
                
                // 尝试使用JavaScript内置日期解析
                const date = new Date(dateStr);
                if (!isNaN(date.getTime())) {
                    return date;
                }
                
                // 如果所有解析都失败，返回null
                return null;
            }
            
            // 获取Z值（基于置信水平）
            function getZValue(confidenceLevel) {
                // 常用置信水平对应的Z值
                const zValues = {
                    80: 1.282,
                    85: 1.440,
                    90: 1.645,
                    95: 1.960,
                    99: 2.576
                };
                
                // 如果置信水平在常用值中，直接返回对应的Z值
                if (zValues[confidenceLevel]) {
                    return zValues[confidenceLevel];
                }
                
                // 对于其他值，使用线性插值近似
                const levels = Object.keys(zValues).map(Number).sort((a, b) => a - b);
                if (confidenceLevel <= levels[0]) return zValues[levels[0]];
                if (confidenceLevel >= levels[levels.length - 1]) return zValues[levels[levels.length - 1]];
                
                // 找到最近的较低和较高置信水平
                let lower = levels[0];
                let higher = levels[levels.length - 1];
                
                for (let i = 0; i < levels.length - 1; i++) {
                    if (confidenceLevel >= levels[i] && confidenceLevel <= levels[i + 1]) {
                        lower = levels[i];
                        higher = levels[i + 1];
                        break;
                    }
                }
                
                // 线性插值
                const ratio = (confidenceLevel - lower) / (higher - lower);
                return zValues[lower] + ratio * (zValues[higher] - zValues[lower]);
            }
            
            // 预测函数
            function predict(data, futurePoints, predictionType, algorithm, confidenceLevel, manualPeriod, manualPeriodValue, dataFrequency, dateFormat, enableRandomness, randomnessRange) {
                // 转换为时间序列索引
                const n = data.length;
                const x = Array.from({length: n}, (_, i) => i);
                const y = data.map(d => d.value);
                
                // 获取Z值
                const zValue = getZValue(confidenceLevel);
                
                // 检测周期性
                let period;
                
                if (manualPeriod) {
                    // 使用手动设置的周期
                    period = manualPeriodValue;
                } else {
                    // 自动检测周期，考虑数据频率
                    period = detectPeriodicity(y, dataFrequency);
                }
                
                const isSeasonal = period > 1 && predictionType !== 'linear';
                
                // 根据预测类型和算法选择预测方法
                let predictions;
                let confidenceIntervals;
                let detectedType;
                
                if (predictionType === 'linear' || (predictionType === 'auto' && !isSeasonal)) {
                    if (algorithm === 'yoy') {
                        const result = latestYoyPrediction(x, y, period, futurePoints, zValue, enableRandomness, randomnessRange);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = `环比增长预测${enableRandomness ? ' (随机波动±' + (randomnessRange*100) + '%)' : ''}`;
                    } else if (algorithm === 'logarithmic') {
                        const result = logarithmicRegression(x, y, futurePoints, zValue);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = '对数线性回归';
                    } else if (algorithm === 'exponential') {
                        const result = exponentialSmoothing(x, y, futurePoints, zValue);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = '指数平滑法';
                    } else {
                        const result = polynomialRegression(x, y, futurePoints, zValue);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = '多项式回归';
                    }
                } else {
                    if (algorithm === 'yoy') {
                        const result = latestYoyPrediction(x, y, period, futurePoints, zValue, enableRandomness, randomnessRange);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = `环比增长预测 (周期=${period})${enableRandomness ? ' (随机波动±' + (randomnessRange*100) + '%)' : ''}`;
                    } else if (algorithm === 'logarithmic') {
                        const result = seasonalLogarithmicPrediction(x, y, period, futurePoints, zValue);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = `季节性对数预测 (周期=${period})`;
                    } else if (algorithm === 'exponential') {
                        const result = seasonalExponentialSmoothing(x, y, period, futurePoints, zValue);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = `季节性指数平滑 (周期=${period})`;
                    } else {
                        const result = seasonalPolynomialPrediction(x, y, period, futurePoints, zValue);
                        predictions = result.predictions;
                        confidenceIntervals = result.confidenceIntervals;
                        detectedType = `季节性多项式预测 (周期=${period})`;
                    }
                }
                
                // 确保预测值为正
                predictions = predictions.map(p => Math.max(0, p));
                
                // 生成未来日期，保持与原始数据相同的格式和间隔
                const lastDate = new Date(data[data.length - 1].date);
                const futureDates = [];
                
                // 优先使用“最近一次实际间隔”确定步长（更贴近真实节律）
                let stepDays = 1;
                if (data.length >= 2) {
                    const lastIntervalDays = (data[data.length - 1].date - data[data.length - 2].date) / (1000 * 60 * 60 * 24);
                    stepDays = Math.round(lastIntervalDays);
                }
                
                // 基于日期格式与步长，选择合适的时间单位推进，避免按毫秒导致月份重复
                function addStep(baseDate, stepIndex) {
                    const d = new Date(baseDate);
                    if (dateFormat === 'yyyy-mm' || (dataFrequency.type === 'monthly' && stepDays >= 28 && stepDays <= 31)) {
                        d.setMonth(baseDate.getMonth() + stepIndex);
                        return d;
                    }
                    if (dataFrequency.type === 'yearly' || stepDays >= 360) {
                        d.setFullYear(baseDate.getFullYear() + stepIndex);
                        return d;
                    }
                    if (dataFrequency.type === 'weekly' || Math.abs(stepDays - 7) <= 1) {
                        d.setDate(baseDate.getDate() + stepIndex * 7);
                        return d;
                    }
                    // 默认按天推进
                    d.setDate(baseDate.getDate() + stepIndex * stepDays);
                    return d;
                }
                
                for (let i = 1; i <= futurePoints; i++) {
                    const futureDate = addStep(lastDate, i);
                    futureDates.push(formatDate(futureDate, dateFormat));
                }
                
                return {
                    futureDates: futureDates,
                    predictions: predictions,
                    confidenceIntervals: confidenceIntervals,
                    type: detectedType,
                    period: period,
                    isSeasonal: isSeasonal,
                    algorithm: algorithm,
                    confidenceLevel: confidenceLevel,
                    dataFrequency: dataFrequency
                };
            }
            
            // 格式化日期为字符串，保持与原始数据相同的格式
            function formatDate(date, dateFormat) {
                const year = date.getFullYear();
                const month = String(date.getMonth() + 1).padStart(2, '0');
                const day = String(date.getDate()).padStart(2, '0');
                
                // 根据检测到的日期格式进行格式化
                if (dateFormat === 'yyyy-mm-dd') {
                    return `${year}-${month}-${day}`;
                } else if (dateFormat === 'yyyy/mm/dd') {
                    return `${year}/${month}/${day}`;
                } else if (dateFormat === 'yyyy-mm') {
                    return `${year}-${month}`;
                } else if (dateFormat === 'yyyy/mm') {
                    return `${year}/${month}`;
                } else {
                    // 默认格式
                    return `${year}-${month}-${day}`;
                }
            }
            
            // 将检测到的周期吸附到常见周期（例如月度数据吸附到12）
            function snapPeriod(period, dataFrequency, n) {
                if (period <= 1) return 1;
                const maxValid = Math.floor(n / 2);
                let p = Math.min(period, maxValid);
                if (dataFrequency && dataFrequency.type === 'monthly') {
                    const candidates = [12, 6, 3];
                    let best = p;
                    let bestDiff = Infinity;
                    for (const c of candidates) {
                        const diff = Math.abs(p - c);
                        if (diff < bestDiff) { bestDiff = diff; best = c; }
                    }
                    if (bestDiff <= 1) return best;
                    if (bestDiff <= 2) return best;
                }
                if (dataFrequency && dataFrequency.type === 'weekly') {
                    const candidates = [52, 26, 13, 4];
                    let best = p; let bestDiff = Infinity;
                    for (const c of candidates) { const d = Math.abs(p - c); if (d < bestDiff) { bestDiff = d; best = c; } }
                    if (bestDiff <= 1) return best;
                }
                if (dataFrequency && dataFrequency.type === 'daily') {
                    const candidates = [7, 14, 30];
                    let best = p; let bestDiff = Infinity;
                    for (const c of candidates) { const d = Math.abs(p - c); if (d < bestDiff) { bestDiff = d; best = c; } }
                    if (bestDiff <= 1) return best;
                }
                return p;
            }
            
            // 检测周期性函数（考虑数据频率并基于波峰检测）
            function detectPeriodicity(y, dataFrequency) {
                const n = y.length;
                if (n < 5) {
                    // 数据太少：按频率给出常见周期
                    if (dataFrequency && dataFrequency.type === 'monthly') return 12;
                    if (dataFrequency && dataFrequency.type === 'weekly') return 7; // 以天为单位时常用每周7
                    if (dataFrequency && dataFrequency.type === 'daily') return 7;
                    return 1;
                }
                
                // 1) 找出多个波峰的时间索引（使用平滑+显著性）
                const windowSize = Math.max(3, Math.floor(n / 20));
                const smoothed = [];
                for (let i = 0; i < n; i++) {
                    let sum = 0, count = 0;
                    const half = Math.floor(windowSize / 2);
                    for (let j = Math.max(0, i - half); j <= Math.min(n - 1, i + half); j++) {
                        sum += y[j]; count++;
                    }
                    smoothed.push(sum / count);
                }
                const peaks = [];
                const amplitude = Math.max(...smoothed) - Math.min(...smoothed);
                const minProminence = amplitude * 0.15;
                for (let i = 1; i < n - 1; i++) {
                    if (smoothed[i] > smoothed[i - 1] && smoothed[i] > smoothed[i + 1]) {
                        const leftMin = Math.min(...smoothed.slice(Math.max(0, i - 5), i));
                        const rightMin = Math.min(...smoothed.slice(i + 1, Math.min(n, i + 6)));
                        const prominence = smoothed[i] - Math.max(leftMin, rightMin);
                        if (prominence > minProminence) {
                            peaks.push(i);
                        }
                    }
                }
                
                // 若波峰不足两个，按频率返回常用周期
                if (peaks.length < 2) {
                    if (dataFrequency && dataFrequency.type === 'monthly') return 12;
                    if (dataFrequency && dataFrequency.type === 'weekly') return 7;
                    if (dataFrequency && dataFrequency.type === 'daily') return 7;
                    return 1;
                }
                
                // 2) 用时间索引的差进行平均值取整
                const intervals = [];
                for (let i = 1; i < peaks.length; i++) {
                    intervals.push(peaks[i] - peaks[i - 1]);
                }
                const avg = Math.round(intervals.reduce((a, b) => a + b, 0) / intervals.length);
                
                // 将平均结果吸附到常见周期集合（7,12,30,60,90等）
                const candidates = [7, 12, 30, 60, 90];
                let best = avg, bestDiff = Infinity;
                for (const c of candidates) {
                    const d = Math.abs(avg - c);
                    if (d < bestDiff) { bestDiff = d; best = c; }
                }
                // 如果距离很近（≤2）则吸附；否则使用平均值本身
                const period = (bestDiff <= 2) ? best : avg;
                
                // 合理性约束：周期不能超过数据长度的一半
                const finalPeriod = Math.min(period, Math.floor(n / 2));
                return finalPeriod > 1 ? finalPeriod : 1;
            }
            
            // 通过波峰检测自动计算周期
            function detectPeriodByPeaks(y) {
                const n = y.length;
                if (n < 5) return 1;
                
                // 第一步：数据平滑（移动平均，减少噪声）
                const windowSize = Math.max(3, Math.floor(n / 20));
                const smoothed = [];
                
                for (let i = 0; i < n; i++) {
                    let sum = 0;
                    let count = 0;
                    const halfWindow = Math.floor(windowSize / 2);
                    
                    for (let j = Math.max(0, i - halfWindow); j <= Math.min(n - 1, i + halfWindow); j++) {
                        sum += y[j];
                        count++;
                    }
                    smoothed.push(sum / count);
                }
                
                // 第二步：检测波峰（局部最大值）
                const peaks = [];
                const minProminence = (Math.max(...smoothed) - Math.min(...smoothed)) * 0.15; // 显著性阈值：15%
                
                for (let i = 1; i < n - 1; i++) {
                    // 检查是否为局部最大值
                    if (smoothed[i] > smoothed[i - 1] && smoothed[i] > smoothed[i + 1]) {
                        // 检查显著性（与周围的差距）
                        const leftMin = Math.min(...smoothed.slice(Math.max(0, i - 5), i));
                        const rightMin = Math.min(...smoothed.slice(i + 1, Math.min(n, i + 6)));
                        const prominence = smoothed[i] - Math.max(leftMin, rightMin);
                        
                        if (prominence > minProminence) {
                            peaks.push({
                                index: i,
                                value: smoothed[i],
                                prominence: prominence
                            });
                        }
                    }
                }
                
                // 第三步：计算波峰间隔
                if (peaks.length < 2) {
                    return 1; // 波峰太少，无法确定周期
                }
                
                const intervals = [];
                for (let i = 1; i < peaks.length; i++) {
                    intervals.push(peaks[i].index - peaks[i - 1].index);
                }
                
                // 第四步：统计最常见的间隔（众数）
                const intervalCounts = {};
                const tolerance = 2; // 允许±2的误差
                
                for (const interval of intervals) {
                    let found = false;
                    for (const key in intervalCounts) {
                        if (Math.abs(interval - parseInt(key)) <= tolerance) {
                            intervalCounts[key]++;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        intervalCounts[interval] = 1;
                    }
                }
                
                // 找到出现次数最多的间隔（主周期）
                let maxCount = 0;
                let bestInterval = 1;
                
                for (const interval in intervalCounts) {
                    if (intervalCounts[interval] > maxCount) {
                        maxCount = intervalCounts[interval];
                        bestInterval = parseInt(interval);
                    }
                }
                
                // 基于多个周期的平均值作为最终周期（更客观）
                let averagedPeriod = bestInterval;
                if (intervals.length >= 2) {
                    // 取与主周期接近（±tolerance）的所有间隔，做均值
                    const cluster = intervals.filter(iv => Math.abs(iv - bestInterval) <= tolerance);
                    if (cluster.length >= 2) {
                        averagedPeriod = Math.round(cluster.reduce((a, b) => a + b, 0) / cluster.length);
                    }
                    // 若有最近的多个周期，优先用最近3个内的均值
                    const recent = intervals.slice(-3);
                    const recentCluster = recent.filter(iv => Math.abs(iv - bestInterval) <= tolerance);
                    if (recentCluster.length >= 2) {
                        averagedPeriod = Math.round(recentCluster.reduce((a, b) => a + b, 0) / recentCluster.length);
                    }
                }
                
                // 第五步：验证合理性
                // 至少要有2个完整周期
                if (averagedPeriod > 1 && averagedPeriod < n / 2 && maxCount >= 2) {
                    console.log(`🔍 波峰检测：发现 ${peaks.length} 个波峰，主间隔 = ${bestInterval} (出现 ${maxCount} 次)，平均周期 = ${averagedPeriod}`);
                    return averagedPeriod;
                }
                
                return 1; // 无明显周期
            }
            
            // 计算平均值
            function mean(arr) {
                return arr.reduce((a, b) => a + b, 0) / arr.length;
            }
            
            // 环比增长预测（YoY: Year-over-Year / Period-over-Period）
            function yoyPrediction(x, y, period, futurePoints, zValue, enableRandomness = false, randomnessRange = 0.05) {
                const n = y.length;
                
                // 计算环比增长率（同期对比）
                const growthRates = [];
                const weights = [];
                
                for (let i = period; i < n; i++) {
                    const prevValue = y[i - period];  // 上一个周期的同期值
                    const currValue = y[i];            // 当前值
                    
                    if (prevValue > 0) {
                        const rate = currValue / prevValue;  // 增长倍数
                        // 指数加权：越近的数据权重越大
                        const weight = Math.exp((i - n) / (n / 3));
                        growthRates.push(rate);
                        weights.push(weight);
                    }
                }
                
                // 计算加权平均增长率
                let avgGrowthRate = 1.0;
                if (growthRates.length > 0) {
                    const weightedSum = growthRates.reduce((sum, rate, idx) => sum + rate * weights[idx], 0);
                    const totalWeight = weights.reduce((sum, w) => sum + w, 0);
                    avgGrowthRate = weightedSum / totalWeight;
                }
                
                // 计算最近一个周期的平滑增长率（用于短期趋势）
                let recentTrend = 1.0;
                if (n >= 2) {
                    const recentGrowths = [];
                    for (let i = Math.max(1, n - period); i < n; i++) {
                        if (y[i - 1] > 0) {
                            recentGrowths.push(y[i] / y[i - 1]);
                        }
                    }
                    if (recentGrowths.length > 0) {
                        recentTrend = recentGrowths.reduce((a, b) => a + b, 0) / recentGrowths.length;
                    }
                }
                
                // 混合长期和短期趋势
                const trendBlend = 0.7;  // 70%长期，30%短期
                const blendedGrowthRate = avgGrowthRate * trendBlend + recentTrend * (1 - trendBlend);
                
                // 生成预测
                const predictions = [];
                const confidenceIntervals = [];
                
                // 计算历史拟合误差（用于置信区间）
                const residuals = [];
                for (let i = period; i < n; i++) {
                    const predicted = y[i - period] * avgGrowthRate;
                    residuals.push((y[i] - predicted) / Math.max(y[i], 1));  // 相对误差
                }
                
                const residualStd = residuals.length > 0 ? 
                    Math.sqrt(residuals.reduce((sum, res) => sum + res * res, 0) / residuals.length) : 0.1;
                
                // 预测未来值
                for (let i = 0; i < futurePoints; i++) {
                    // 找到对应的历史同期数据
                    const baseIndex = n - period + (i % period);
                    let baseValue;
                    
                    if (baseIndex >= 0 && baseIndex < n) {
                        baseValue = y[baseIndex];
                    } else {
                        // 如果超出历史数据范围，使用最近的预测值
                        baseValue = i > 0 ? predictions[i - period] : y[n - 1];
                    }
                    
                    // 应用增长率
                    let predicted = baseValue * blendedGrowthRate;
                    
                    // 添加随机波动（如果启用）
                    if (enableRandomness && randomnessRange > 0) {
                        // 使用Box-Muller变换生成正态分布随机数
                        const u1 = Math.random();
                        const u2 = Math.random();
                        const randNormal = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2);
                        
                        // 将随机数限制在[-1, 1]范围内，然后缩放到指定范围
                        const clampedRand = Math.max(-1, Math.min(1, randNormal / 3));
                        const randomFactor = 1 + clampedRand * randomnessRange;
                        
                        predicted *= randomFactor;
                    }
                    
                    predicted = Math.max(0, predicted);
                    predictions.push(predicted);
                    
                    // 计算置信区间
                    const se = residualStd * predicted * Math.sqrt(1 + (i + 1) / n);
                    const lower = Math.max(0, predicted - zValue * se);
                    const upper = predicted + zValue * se;
                    confidenceIntervals.push({ lower, upper });
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 最新值环比增长预测（按用户定义）
            function latestYoyPrediction(x, y, period, futurePoints, zValue, enableRandomness = false, randomnessRange = 0.05) {
                const n = y.length;
                // 计算“最近最多三个周期的均比率”（更客观）
                let ratio = 1.0;
                const latestRatios = [];
                if (period > 0) {
                    const maxCycles = Math.min(3, Math.floor((n - 1) / period));
                    for (let j = 1; j <= maxCycles; j++) {
                        const currIdx = n - 1 - (j - 1) * period;
                        const prevIdx = n - 1 - j * period;
                        if (prevIdx >= 0 && y[prevIdx] > 0) {
                            latestRatios.push(y[currIdx] / y[prevIdx]);
                        }
                    }
                    if (latestRatios.length > 0) {
                        ratio = latestRatios.reduce((s, v) => s + v, 0) / latestRatios.length;
                    } else if (n - 1 - period >= 0 && y[n - 1 - period] > 0) {
                        ratio = y[n - 1] / y[n - 1 - period];
                    }
                }
                
                const predictions = [];
                const confidenceIntervals = [];
                
                // 基于最近最多三个周期的“同期环比率”估计波动（用于置信区间）
                let relStd = 0.1; // 默认10%
                if (period > 0 && n > period) {
                    const rates = [];
                    const maxCycles = Math.min(3, Math.floor((n - 1) / period));
                    for (let j = 1; j <= maxCycles; j++) {
                        for (let k = 0; k < period; k++) {
                            const aIdx = n - 1 - (j - 1) * period - k;
                            const bIdx = n - 1 - j * period - k;
                            if (aIdx >= 0 && bIdx >= 0 && y[bIdx] > 0) {
                                rates.push(y[aIdx] / y[bIdx]);
                            }
                        }
                    }
                    if (rates.length > 1) {
                        const m = rates.reduce((s, v) => s + v, 0) / rates.length;
                        const varr = rates.reduce((s, v) => s + (v - m) * (v - m), 0) / (rates.length - 1);
                        relStd = Math.sqrt(varr);
                    }
                }
                
                for (let i = 0; i < futurePoints; i++) {
                    const baseIndex = n - period + (i % period);
                    let baseValue;
                    if (baseIndex >= 0 && baseIndex < n) {
                        baseValue = y[baseIndex];
                    } else {
                        baseValue = i > 0 ? predictions[Math.max(0, i - period)] : y[n - 1];
                    }
                    
                    let predicted = Math.max(0, baseValue * ratio);
                    
                    // 启用“随机波动”时，使预测值落在 ±randomnessRange 范围内随机波动
                    if (enableRandomness && randomnessRange > 0) {
                        const factor = 1 + (Math.random() * 2 - 1) * randomnessRange; // 线性均匀分布 [-r, +r]
                        predicted *= factor;
                    }
                    predictions.push(predicted);
                    
                    // 置信区间：优先使用“波动范围”表达（符合“加减波动范围”的描述）
                    if (randomnessRange > 0) {
                        const lower = Math.max(0, predicted * (1 - randomnessRange));
                        const upper = predicted * (1 + randomnessRange);
                        confidenceIntervals.push({ lower, upper });
                    } else {
                        // 否则按最近环比波动的相对标准差构造
                        const se = predicted * relStd;
                        const lower = Math.max(0, predicted - zValue * se);
                        const upper = predicted + zValue * se;
                        confidenceIntervals.push({ lower, upper });
                    }
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 对数回归预测（确保正值）
            function logarithmicRegression(x, y, futurePoints, zValue) {
                const n = x.length;
                
                // 对y值取对数（避免0值）
                const logY = y.map(val => Math.log(Math.max(val, 1)));
                
                // 计算均值
                const xMean = mean(x);
                const yLogMean = mean(logY);
                
                // 计算斜率和截距
                let numerator = 0;
                let denominator = 0;
                
                for (let i = 0; i < n; i++) {
                    numerator += (x[i] - xMean) * (logY[i] - yLogMean);
                    denominator += (x[i] - xMean) ** 2;
                }
                
                const slope = numerator / denominator;
                const intercept = yLogMean - slope * xMean;
                
                // 生成预测
                const predictions = [];
                const confidenceIntervals = [];
                
                // 计算残差
                const residuals = [];
                for (let i = 0; i < n; i++) {
                    const predictedLog = intercept + slope * x[i];
                    const predicted = Math.exp(predictedLog);
                    residuals.push(y[i] - predicted);
                }
                
                // 计算残差标准差
                const residualStd = Math.sqrt(residuals.reduce((sum, res) => sum + res * res, 0) / (n - 2));
                
                for (let i = 0; i < futurePoints; i++) {
                    const futureX = n + i;
                    const predictedLog = intercept + slope * futureX;
                    const predicted = Math.exp(predictedLog);
                    predictions.push(predicted);
                    
                    // 计算置信区间
                    const se = residualStd * Math.sqrt(1 + 1/n + Math.pow(futureX - xMean, 2) / 
                        (x.reduce((sum, xi) => sum + Math.pow(xi - xMean, 2), 0)));
                    
                    const lower = Math.max(0, Math.exp(predictedLog - zValue * se));
                    const upper = Math.exp(predictedLog + zValue * se);
                    confidenceIntervals.push({ lower, upper });
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 指数平滑法
            function exponentialSmoothing(x, y, futurePoints, zValue, alpha = 0.3) {
                const n = y.length;
                let smoothed = [y[0]];
                
                // 应用指数平滑
                for (let i = 1; i < n; i++) {
                    smoothed.push(alpha * y[i] + (1 - alpha) * smoothed[i - 1]);
                }
                
                // 计算趋势
                let trend = 0;
                if (n > 1) {
                    trend = (smoothed[n - 1] - smoothed[0]) / (n - 1);
                }
                
                // 生成预测
                const predictions = [];
                const confidenceIntervals = [];
                let lastValue = smoothed[n - 1];
                
                // 计算残差
                const residuals = [];
                for (let i = 0; i < n; i++) {
                    residuals.push(y[i] - smoothed[i]);
                }
                
                // 计算残差标准差
                const residualStd = Math.sqrt(residuals.reduce((sum, res) => sum + res * res, 0) / n);
                
                for (let i = 0; i < futurePoints; i++) {
                    lastValue = lastValue + trend;
                    predictions.push(lastValue);
                    
                    // 计算置信区间
                    const se = residualStd * Math.sqrt(i + 1);
                    const lower = Math.max(0, lastValue - zValue * se);
                    const upper = lastValue + zValue * se;
                    confidenceIntervals.push({ lower, upper });
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 多项式回归
            function polynomialRegression(x, y, futurePoints, zValue, degree = 2) {
                // 准备数据点
                const points = x.map((xi, i) => [xi, y[i]]);
                
                // 使用回归库进行多项式回归
                const result = regression.polynomial(points, { order: degree, precision: 10 });
                
                // 生成预测
                const predictions = [];
                const confidenceIntervals = [];
                const n = x.length;
                
                // 计算残差
                const residuals = [];
                for (let i = 0; i < n; i++) {
                    const predicted = result.predict(x[i])[1];
                    residuals.push(y[i] - predicted);
                }
                
                // 计算残差标准差
                const residualStd = Math.sqrt(residuals.reduce((sum, res) => sum + res * res, 0) / (n - degree - 1));
                
                for (let i = 0; i < futurePoints; i++) {
                    const futureX = n + i;
                    const predicted = Math.max(0, result.predict(futureX)[1]);
                    predictions.push(predicted);
                    
                    // 计算置信区间
                    const se = residualStd * Math.sqrt(1 + 1/n);
                    const lower = Math.max(0, predicted - zValue * se);
                    const upper = predicted + zValue * se;
                    confidenceIntervals.push({ lower, upper });
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 季节性对数预测（优化版：从最近数据状态出发）
            function seasonalLogarithmicPrediction(x, y, period, futurePoints, zValue) {
                const n = y.length;
                
                // 对y值取对数（避免0值）
                const logY = y.map(val => Math.log(Math.max(val, 1)));
                
                // 使用线性回归计算趋势
                const xMean = mean(x);
                const yLogMean = mean(logY);
                
                let numerator = 0;
                let denominator = 0;
                
                for (let i = 0; i < n; i++) {
                    numerator += (x[i] - xMean) * (logY[i] - yLogMean);
                    denominator += (x[i] - xMean) ** 2;
                }
                
                const slope = numerator / denominator;
                const intercept = yLogMean - slope * xMean;
                
                // 去趋势化
                const detrended = [];
                for (let i = 0; i < n; i++) {
                    const trendValue = intercept + slope * x[i];
                    detrended.push(logY[i] - trendValue);
                }
                
                // 计算季节性成分（更重视最近数据）
                const seasonalComponents = Array(period).fill(0);
                const seasonalWeights = Array(period).fill(0);
                
                for (let i = 0; i < n; i++) {
                    const seasonIndex = i % period;
                    // 指数衰减权重:越近的数据权重越大
                    const weight = Math.exp((i - n) / (n / 3));
                    seasonalComponents[seasonIndex] += detrended[i] * weight;
                    seasonalWeights[seasonIndex] += weight;
                }
                
                // 加权平均季节性成分
                for (let i = 0; i < period; i++) {
                    if (seasonalWeights[i] > 0) {
                        seasonalComponents[i] /= seasonalWeights[i];
                    }
                }
                
                // 标准化季节性成分
                const seasonalMean = mean(seasonalComponents);
                const normalizedSeasonals = seasonalComponents.map(s => s - seasonalMean);
                
                // 计算最后一个数据点的校准偏移
                const lastSeasonIndex = (n - 1) % period;
                const lastTrendLog = intercept + slope * (n - 1);
                const lastExpectedLog = lastTrendLog + normalizedSeasonals[lastSeasonIndex];
                const lastActualLog = logY[n - 1];
                const calibrationOffset = lastActualLog - lastExpectedLog;
                
                // 应用季节性因子
                const predictions = [];
                const confidenceIntervals = [];
                
                // 计算残差
                const residuals = [];
                for (let i = 0; i < n; i++) {
                    const seasonIndex = i % period;
                    const predictedLog = intercept + slope * x[i] + normalizedSeasonals[seasonIndex];
                    const predicted = Math.exp(predictedLog);
                    residuals.push(y[i] - predicted);
                }
                
                // 计算残差标准差
                const residualStd = Math.sqrt(residuals.reduce((sum, res) => sum + res * res, 0) / Math.max(n - 2, 1));
                
                for (let i = 0; i < futurePoints; i++) {
                    const futureX = n + i;
                    const seasonIndex = (n + i) % period;
                    let predictedLog = intercept + slope * futureX + normalizedSeasonals[seasonIndex];
                    
                    // 应用校准偏移量（逐步衰减）
                    const decayFactor = Math.exp(-i / period);
                    predictedLog += calibrationOffset * decayFactor;
                    
                    const predicted = Math.exp(predictedLog);
                    predictions.push(predicted);
                    
                    // 计算置信区间
                    const se = residualStd * Math.sqrt(1 + 1/n + Math.pow(futureX - xMean, 2) / 
                        Math.max(x.reduce((sum, xi) => sum + Math.pow(xi - xMean, 2), 0), 1));
                    
                    const lower = Math.max(0, Math.exp(predictedLog - zValue * se));
                    const upper = Math.exp(predictedLog + zValue * se);
                    confidenceIntervals.push({ lower, upper });
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 季节性指数平滑（优化版：自然延续最近状态）
            function seasonalExponentialSmoothing(x, y, period, futurePoints, zValue, alpha = 0.3, beta = 0.1, gamma = 0.2) {
                const n = y.length;
                
                // 初始化水平、趋势和季节性分量
                let level = mean(y.slice(0, Math.min(period, n)));
                let trend = 0;
                
                // 初始化季节性分量（使用更稳健的方法）
                const seasonals = Array(period).fill(1);
                const seasonalSums = Array(period).fill(0);
                const seasonalCounts = Array(period).fill(0);
                
                for (let i = 0; i < n; i++) {
                    const seasonIndex = i % period;
                    seasonalSums[seasonIndex] += y[i];
                    seasonalCounts[seasonIndex]++;
                }
                
                const avgLevel = mean(y);
                for (let i = 0; i < period; i++) {
                    if (seasonalCounts[i] > 0) {
                        seasonals[i] = (seasonalSums[i] / seasonalCounts[i]) / avgLevel;
                    }
                }
                
                // 应用Holt-Winters季节性指数平滑
                const smoothed = [];
                
                for (let i = 0; i < n; i++) {
                    const seasonIndex = i % period;
                    const prevLevel = level;
                    
                    // 更新公式
                    level = alpha * (y[i] / seasonals[seasonIndex]) + (1 - alpha) * (prevLevel + trend);
                    trend = beta * (level - prevLevel) + (1 - beta) * trend;
                    seasonals[seasonIndex] = gamma * (y[i] / level) + (1 - gamma) * seasonals[seasonIndex];
                    
                    smoothed.push((prevLevel + trend) * seasonals[seasonIndex]);
                }
                
                // 计算最后一个点的实际偏差（用于校准）
                const lastSeasonIndex = (n - 1) % period;
                const lastExpected = (level + trend) * seasonals[lastSeasonIndex];
                const lastActual = y[n - 1];
                const calibrationRatio = lastActual / Math.max(lastExpected, 1); // 比例校准
                
                // 生成预测
                const predictions = [];
                const confidenceIntervals = [];
                
                // 计算残差
                const residuals = [];
                for (let i = 0; i < n; i++) {
                    residuals.push(y[i] - smoothed[i]);
                }
                
                // 计算残差标准差
                const residualStd = Math.sqrt(residuals.reduce((sum, res) => sum + res * res, 0) / Math.max(n, 1));
                
                for (let i = 0; i < futurePoints; i++) {
                    const seasonIndex = (n + i) % period;
                    let predicted = (level + (i + 1) * trend) * seasonals[seasonIndex];
                    
                    // 应用校准比例（逐步衰减嘰1）
                    const decayFactor = Math.exp(-i / period);
                    const adjustedRatio = 1 + (calibrationRatio - 1) * decayFactor;
                    predicted *= adjustedRatio;
                    
                    predicted = Math.max(0, predicted);
                    predictions.push(predicted);
                    
                    // 计算置信区间
                    const se = residualStd * Math.sqrt(i + 1);
                    const lower = Math.max(0, predicted - zValue * se);
                    const upper = predicted + zValue * se;
                    confidenceIntervals.push({ lower, upper });
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 季节性多项式预测（优化版：从最近数据状态出发）
            function seasonalPolynomialPrediction(x, y, period, futurePoints, zValue, degree = 2) {
                const n = y.length;
                
                // 去趋势化：移除整体趋势
                const points = x.map((xi, i) => [xi, y[i]]);
                const trendResult = regression.polynomial(points, { order: degree, precision: 10 });
                
                // 计算去趋势后的数据
                const detrended = [];
                for (let i = 0; i < n; i++) {
                    const trendValue = trendResult.predict(x[i])[1];
                    detrended.push(y[i] - trendValue);
                }
                
                // 计算季节性成分（更重视最近数据）
                const seasonalComponents = Array(period).fill(0);
                const seasonalWeights = Array(period).fill(0);
                
                for (let i = 0; i < n; i++) {
                    const seasonIndex = i % period;
                    // 指数衰减权重:越近的数据权重越大
                    const weight = Math.exp((i - n) / (n / 3)); // 最近1/3数据权重显著增加
                    seasonalComponents[seasonIndex] += detrended[i] * weight;
                    seasonalWeights[seasonIndex] += weight;
                }
                
                // 加权平均季节性成分
                for (let i = 0; i < period; i++) {
                    if (seasonalWeights[i] > 0) {
                        seasonalComponents[i] /= seasonalWeights[i];
                    }
                }
                
                // 标准化季节性成分（使其和为0，保持总体水平不变）
                const seasonalMean = mean(seasonalComponents);
                const normalizedSeasonals = seasonalComponents.map(s => s - seasonalMean);
                
                // 计算最后一个数据点的实际偏差（用于校准起点）
                const lastSeasonIndex = (n - 1) % period;
                const lastTrend = trendResult.predict(n - 1)[1];
                const lastExpected = lastTrend + normalizedSeasonals[lastSeasonIndex];
                const lastActual = y[n - 1];
                const calibrationOffset = lastActual - lastExpected; // 校准偏移量
                
                // 应用季节性和趋势进行预测
                const predictions = [];
                const confidenceIntervals = [];
                
                // 计算拟合误差
                const residuals = [];
                for (let i = 0; i < n; i++) {
                    const seasonIndex = i % period;
                    const trendValue = trendResult.predict(x[i])[1];
                    const predicted = trendValue + normalizedSeasonals[seasonIndex];
                    residuals.push(y[i] - predicted);
                }
                
                // 计算残差标准差
                const residualStd = Math.sqrt(residuals.reduce((sum, res) => sum + res * res, 0) / Math.max(n - degree - 1, 1));
                
                // 生成预测值（从最近数据状态平滑过渡）
                for (let i = 0; i < futurePoints; i++) {
                    const futureX = n + i;
                    const seasonIndex = (n + i) % period;
                    
                    // 趋势预测
                    const trendValue = trendResult.predict(futureX)[1];
                    
                    // 加上季节性成分
                    let predicted = trendValue + normalizedSeasonals[seasonIndex];
                    
                    // 应用校准偏移量（逐步衰减,确保从最近数据平滑过渡）
                    const decayFactor = Math.exp(-i / period); // 一个周期后衰减到约37%
                    predicted += calibrationOffset * decayFactor;
                    
                    predicted = Math.max(0, predicted);
                    predictions.push(predicted);
                    
                    // 计算置信区间
                    const se = residualStd * Math.sqrt(1 + 1/n + Math.pow(i + 1, 2) / (n * n));
                    const lower = Math.max(0, predicted - zValue * se);
                    const upper = predicted + zValue * se;
                    confidenceIntervals.push({ lower, upper });
                }
                
                return { predictions, confidenceIntervals };
            }
            
            // 显示预测信息
            function displayPredictionInfo(result, dataFrequency) {
                const infoElement = document.getElementById('predictionInfo');
                let warning = '';
                
                // 检查周期是否与数据频率匹配
                if (result.isSeasonal) {
                    if (dataFrequency.type === 'daily' && result.period > 30) {
                        warning = '<div class="warning">警告：检测到的周期可能不准确，建议手动调整周期设置</div>';
                    } else if (dataFrequency.type === 'weekly' && result.period > 52) {
                        warning = '<div class="warning">警告：检测到的周期可能不准确，建议手动调整周期设置</div>';
                    } else if (dataFrequency.type === 'monthly' && result.period > 24) {
                        warning = '<div class="warning">警告：检测到的周期可能不准确，建议手动调整周期设置</div>';
                    }
                }
                
                infoElement.innerHTML = `
                    <strong>预测类型:</strong> ${result.type}<br>
                    <strong>检测到的周期:</strong> ${result.period}<br>
                    <strong>使用算法:</strong> ${result.algorithm}<br>
                    <strong>置信水平:</strong> ${result.confidenceLevel}%<br>
                    <strong>预测结果:</strong> 未来${result.futureDates.length}个数据点预测
                    ${warning}
                `;
            }
            
            // 显示表格
            function displayTable(historicalData, predictionResult, showConfidence, xLabel, yLabel) {
                const tableBody = document.getElementById('tableBody');
                tableBody.innerHTML = '';
                
                // 更新表头
                document.getElementById('tableHeaderX').textContent = xLabel;
                document.getElementById('tableHeaderY').textContent = yLabel;
                
                // 添加历史数据
                historicalData.forEach(item => {
                    const row = document.createElement('tr');
                    row.innerHTML = `
                        <td>${item.dateStr}</td>
                        <td>${Math.round(item.value).toLocaleString()}</td>
                        <td>历史数据</td>
                        <td>-</td>
                    `;
                    tableBody.appendChild(row);
                });
                
                // 添加预测数据
                predictionResult.futureDates.forEach((date, index) => {
                    const row = document.createElement('tr');
                    const prediction = Math.round(predictionResult.predictions[index]);
                    const confidence = showConfidence ? 
                        `${Math.round(predictionResult.confidenceIntervals[index].lower).toLocaleString()} - ${Math.round(predictionResult.confidenceIntervals[index].upper).toLocaleString()}` : 
                        '-';
                    
                    row.innerHTML = `
                        <td>${date}</td>
                        <td>${prediction.toLocaleString()}</td>
                        <td>预测数据</td>
                        <td>${confidence}</td>
                    `;
                    tableBody.appendChild(row);
                });
            }
            
            // 显示图表
            function displayChart(historicalData, predictionResult, showConfidence, xLabel, yLabel) {
                const ctx = document.getElementById('predictionChart').getContext('2d');
                
                // 销毁现有图表
                if (predictionChart) {
                    predictionChart.destroy();
                }
                
                // 准备数据
                const labels = [
                    ...historicalData.map(d => d.dateStr),
                    ...predictionResult.futureDates
                ];
                
                const historicalValues = historicalData.map(d => d.value);
                const predictionValues = predictionResult.predictions;
                
                // 创建数据集
                const datasets = [
                    {
                        label: '历史数据',
                        data: [
                            ...historicalValues,
                            ...Array(predictionValues.length).fill(null)
                        ],
                        borderColor: 'rgb(75, 192, 192)',
                        backgroundColor: 'rgba(75, 192, 192, 0.1)',
                        tension: 0.1,
                        fill: false
                    },
                    {
                        label: '预测数据',
                        data: [
                            ...Array(historicalValues.length).fill(null),
                            ...predictionValues
                        ],
                        borderColor: 'rgb(255, 99, 132)',
                        backgroundColor: 'rgba(255, 99, 132, 0.1)',
                        borderDash: [5, 5],
                        tension: 0.1,
                        fill: false
                    }
                ];
                
                // 添加置信区间
                if (showConfidence) {
                    datasets.push({
                        label: `置信区间 (${predictionResult.confidenceLevel}%)`,
                        data: [
                            ...Array(historicalValues.length).fill(null),
                            ...predictionResult.confidenceIntervals.map(ci => ci.upper)
                        ],
                        borderColor: 'rgba(255, 99, 132, 0.3)',
                        backgroundColor: 'rgba(255, 99, 132, 0.1)',
                        borderDash: [2, 2],
                        tension: 0.1,
                        fill: '-1'
                    });
                    
                    datasets.push({
                        label: '',
                        data: [
                            ...Array(historicalValues.length).fill(null),
                            ...predictionResult.confidenceIntervals.map(ci => ci.lower)
                        ],
                        borderColor: 'rgba(255, 99, 132, 0.3)',
                        backgroundColor: 'rgba(255, 99, 132, 0.1)',
                        borderDash: [2, 2],
                        tension: 0.1,
                        fill: '-1'
                    });
                }
                
                // 创建图表
                predictionChart = new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: labels,
                        datasets: datasets
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        scales: {
                            y: {
                                beginAtZero: true,
                                title: {
                                    display: true,
                                    text: yLabel
                                }
                            },
                            x: {
                                title: {
                                    display: true,
                                    text: xLabel
                                }
                            }
                        },
                        plugins: {
                            title: {
                                display: true,
                                text: `${yLabel}预测图表`
                            },
                            tooltip: {
                                callbacks: {
                                    label: function(context) {
                                        return context.dataset.label + ': ' + Math.round(context.parsed.y).toLocaleString();
                                    }
                                }
                            },
                            zoom: {
                                pan: {
                                    enabled: true,
                                    mode: 'x'
                                },
                                zoom: {
                                    wheel: {
                                        enabled: true,
                                    },
                                    pinch: {
                                        enabled: true
                                    },
                                    mode: 'x',
                                }
                            }
                        }
                    }
                });
            }
            
            // 初始预测
            performPrediction();
        });
    </script>
</body>
</html>